package org.lex.expression;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Stack;

import org.lex.expression.tree.ExpressionTree;
import org.lex.expression.tree.Node;

public class Usage implements Runnable {
	public static void main(String[] args) {
		new Usage().run();
	}

	private Lexer lexer = null;
	private ExpressionParser parser = null;
	private ExpressionCalculator caltulator = null;
	private ExpressionTree treeParser = null;

	public void run() {
		boolean exit = false;
		while (false == exit) {
			ln("Type in expression: ");
			String expression = this.readLine();
			this.maybeExitCommand(expression);
			ln("Tokens: ");
			this.lexerTest(expression);
			ln("\nPostfix: ");
			this.parserTest(expression);
			ln("\nTree: ");
			this.treeTest(expression);
			System.out.print("\nResult: ");
			this.calculatorTest(expression);
		}
	}

	void lexerTest(String expr) {
		this.getLexer().setSource(expr);
		while (true) {
			Token token = this.lexer.nextToken();
			if (token.getTokenType() == TokenType.END)
				return;
			ln(token.toString());
		}
	}

	void parserTest(String expression) {
		PostfixExpression postfix = this.getParser().parsePostfix(expression);
		ln(this.toString(postfix.getPostfix()));
	}

	void treeTest(String expression) {
		PostfixExpression postfix = this.getParser().parsePostfix(expression);
		Node node = this.getTreeParser().parseRootNode(postfix);
		node.print(System.out, 2);
	}

	void calculatorTest(String expression) {
		PostfixExpression postfix = this.getParser().parsePostfix(expression);
		Number result = this.getCaltulator().calculate(postfix);
		ln(result + "\n");
	}

	private Lexer getLexer() {
		if (null == this.lexer)
			this.lexer = new Lexer();
		return lexer;
	}

	private ExpressionParser getParser() {
		if (null == parser)
			this.parser = new ExpressionParser();
		return parser;
	}

	private ExpressionTree getTreeParser() {
		if (null == treeParser)
			this.treeParser = new ExpressionTree();
		return treeParser;
	}

	private ExpressionCalculator getCaltulator() {
		if (null == this.caltulator)
			this.caltulator = new ExpressionCalculator();
		return caltulator;
	}

	private void maybeExitCommand(String input) {
		if (input.startsWith("exit") || input.startsWith("quit")) {
			ln("\nBye~");
			System.exit(0);
		}
	}

	private BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));

	private String readLine() {
		try {
			return reader.readLine();
		} catch (IOException e) {
			return this.getDefaultExpression();
		}
	}

	private String getDefaultExpression() {
		// 1 202 31 3 - * 5 / +
		return "1  + 202 * ( 31 - 3 ) / (5)";
	}

	private void ln(String s) {
		System.out.println(s);
	}

	private String toString(Stack<?> stack) {
		StringBuilder buffer = new StringBuilder();
		while (false == stack.empty())
			buffer.append(stack.pop()).append(' ');
		return buffer.toString();
	}
}
